﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;

namespace Tilver.Coder.Utility
{
    public static class DBTypeUtil
    {
        /// <summary>
        /// 可以作为枚举的数据类型
        /// </summary>
        private static readonly HashSet<DbType> EnumDbTypes = new HashSet<DbType> { 
            DbType.Int16, 
            DbType.Int32, 
            DbType.Int64, 
            DbType.UInt16, 
            DbType.UInt32, 
            DbType.UInt64, 
            DbType.Byte, 
            DbType.SByte };

        /// <summary>
        /// 值类型的数据类型
        /// </summary>
        private static readonly HashSet<DbType> ValueDbTypes = new HashSet<DbType> { 
            DbType.Int16, 
            DbType.Int32, 
            DbType.Int64, 
            DbType.UInt16, 
            DbType.UInt32, 
            DbType.UInt64, 
            DbType.Byte, 
            DbType.SByte, 
            DbType.Boolean, 
            DbType.Currency, 
            DbType.Date, 
            DbType.DateTime, 
            DbType.Decimal, 
            DbType.Double, 
            DbType.Guid, 
            DbType.Single, 
            DbType.Time, 
            DbType.VarNumeric, 
            DbType.DateTime2, 
            DbType.DateTimeOffset };
        /// <summary>
        /// 将数据类型转换成对应的c#数据类型
        /// </summary>
        /// <param name="dbType">数据类型</param>
        /// <returns></returns>
        public static string ConvertToCSharpType(DbType dbType)
        {
            return ConvertToCSharpType(dbType, false);
        }

        /// <summary>
        ///将数据类型转换成对应的c#数据类型
        /// </summary>
        /// <param name="dbType">数据类型</param>
        /// <param name="allowDBNull">是否可以为空</param>
        /// <returns></returns>
        public static string ConvertToCSharpType(DbType dbType, bool allowDBNull)
        {
            var ret = string.Empty;
            switch (dbType)
            {
                case DbType.String:
                case DbType.StringFixedLength:
                case DbType.AnsiString:
                case DbType.AnsiStringFixedLength:
                    ret = "string";
                    break;
                case DbType.Binary:
                    ret = "byte[]";
                    break;
                case DbType.Boolean:
                    ret = "bool";
                    break;
                case DbType.Byte:
                    ret = "byte";
                    break;
                case DbType.Decimal:
                case DbType.Currency:
                case DbType.VarNumeric:
                    ret = "decimal";
                    break;
                case DbType.Date:
                case DbType.DateTime:
                case DbType.DateTime2:
                    ret = "DateTime";
                    break;
                case DbType.DateTimeOffset:
                    ret = "DateTimeOffset";
                    break;
                case DbType.Double:
                    ret = "double";
                    break;
                case DbType.Guid:
                    ret = "Guid";
                    break;
                case DbType.Int16:
                    ret = "short";
                    break;
                case DbType.Int32:
                    ret = "int";
                    break;
                case DbType.Int64:
                    ret = "long";
                    break;
                case DbType.Object:
                    ret = "object";
                    break;
                case DbType.SByte:
                    ret = "sbyte";
                    break;
                case DbType.Single:
                    ret = "float";
                    break;
                case DbType.Time:
                    ret = "TimeSpan";
                    break;//?
                case DbType.UInt16:
                    ret = "ushort";
                    break;
                case DbType.UInt32:
                    ret = "uint";
                    break;
                case DbType.UInt64:
                    ret = "ulong";
                    break;
                case DbType.Xml:
                    ret = "string";
                    break;
                default:
                    throw new NotImplementedException("未知的类型");
            }
            //如果字段允许为空，则在类型后加?表示,DateTime?
            if (IsValueType(dbType) && allowDBNull)
                ret += "?";
            return ret;
        }
        /// <summary>
        /// 是否是值类型
        /// </summary>
        /// <param name="dbType"></param>
        /// <returns></returns>
        public static bool IsValueType(DbType dbType)
        {
            return ValueDbTypes.Contains(dbType);
        }
        /// <summary>
        /// 是否可以转换成枚举类型
        /// </summary>
        /// <param name="dbType"></param>
        /// <returns></returns>
        public static bool IsEnumType(DbType dbType)
        {
            return EnumDbTypes.Contains(dbType);
        }

        public static DbType ConvertToDbType(Type t)
        {
            DbType dbt;
            try
            {
                dbt = (DbType)System.Enum.Parse(typeof(DbType), t.Name);
            }
            catch
            {
                try
                {
                    switch (t.Name)
                    {
                        case "Byte[]":
                            dbt = DbType.Binary;
                            break;
                        default:
                            dbt = DbType.Object;
                            break;
                    }

                }
                catch
                {
                    dbt = DbType.Object;
                }
            }
            return dbt;
        }


        /// <summary>
        /// 获得数据列（视图或表）对应的C#类型
        /// </summary>
        /// <param name="column"></param>
        /// <returns></returns>
        public static string GetCSharpType(Type type, bool allowDBNull)
        {
            string ret = string.Empty;

            switch (type.FullName)
            {
                case "System.Int64":
                    ret = "long";
                    break;
                case "System.Byte[]":
                    ret = "byte[]";
                    break;
                case "System.Boolean":
                    ret = "bool";
                    break;
                case "System.String":
                    ret = "string";
                    break;
                case "System.DateTime":
                    ret = "DateTime";
                    break;
                case "System.Decimal":
                    ret = "decimal";
                    break;
                case "System.Double":
                    ret = "double";
                    break;
                case "System.Int32":
                    ret = "int";
                    break;
                case "System.Single":
                    ret = "float";
                    break;
                case "System.Int16":
                    ret = "short";
                    break;
                case "System.Object":
                    ret = "object";
                    break;
                case "System.Byte":
                    ret = "byte";
                    break;
                case "System.Guid":
                    ret = "Guid";
                    break;
                case "System.Xml.XmlDocument":
                    ret = "System.Xml.XmlDocument";
                    break;
                default:
                    ret = type.FullName;
                    break;
            }
            if (type.IsValueType && allowDBNull)
                ret += "?";
            return ret;
        } 
    }
}
